{% extends "console/layout.html" %}
{% block title %}Billing templates · {{ site_name | default('RustPBX') }}{% endblock %}
{% block content %}
{% set base_url = base_path | default('/console') %}
<div class="p-6" x-data='billTemplatesPage({
        basePath: {{ base_url | tojson }},
        filters: {{ filters | default({}) | tojson }},
        createUrl: {{ create_url | tojson }}
    })' x-init="init()">
    <div class="mx-auto max-w-7xl space-y-6">
        <header class="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
            <div class="space-y-1">
                <p class="text-xs font-semibold uppercase tracking-wide text-sky-600">Billing catalog</p>
                <h1 class="text-2xl font-semibold text-slate-900">Billing templates</h1>
                <p class="text-sm text-slate-500">Standardise charging models, allowances, and taxes for trunks and
                    customers.</p>
            </div>
            <a :href="createUrl"
                class="inline-flex items-center gap-2 rounded-lg bg-sky-600 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-400 focus:ring-offset-2">
                <svg class="h-4 w-4" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M10 4v12m6-6H4" />
                </svg>
                New template
            </a>
        </header>

        <template x-if="flash">
            <div class="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-700"
                x-text="flash"></div>
        </template>
        <template x-if="error">
            <div class="rounded-lg border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-600" x-text="error">
            </div>
        </template>

        <section class="rounded-xl bg-white p-5 shadow-sm ring-1 ring-black/5">
            <div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
                <div>
                    <h2 class="text-sm font-semibold text-slate-900">Filters</h2>
                    <p class="text-xs text-slate-500">Search templates or narrow down by currency and billing interval.
                    </p>
                </div>
                <button type="button"
                    class="inline-flex items-center gap-2 rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-semibold text-slate-600 transition hover:border-sky-300 hover:text-sky-700"
                    @click="resetFilters()">
                    <svg class="h-3.5 w-3.5" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6">
                        <path stroke-linecap="round" stroke-linejoin="round" d="M10 3v14m-7-7h14" />
                    </svg>
                    Clear all
                </button>
            </div>

            <div class="mt-4 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
                <label class="flex flex-col gap-2 text-sm font-medium text-slate-700">
                    Search
                    <div class="relative">
                        <svg class="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400"
                            viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.6">
                            <path stroke-linecap="round" stroke-linejoin="round"
                                d="m17.5 17.5-3.65-3.65m0 0a5.5 5.5 0 1 0-7.778-7.778 5.5 5.5 0 0 0 7.778 7.778Z" />
                        </svg>
                        <input type="search" x-model.trim="keyword" @input.debounce.400ms="applyFilters()"
                            class="w-full rounded-lg border border-slate-200 px-3 py-2 pl-9 text-sm text-slate-700 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200"
                            placeholder="Name or display label">
                    </div>
                </label>
                <label class="flex flex-col gap-2 text-sm font-medium text-slate-700">
                    Currency
                    <select x-model="currencyFilter" @change="applyFilters()"
                        class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-700 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                        <template x-for="option in currencyOptions" :key="option.value">
                            <option :value="option.value" x-text="option.label"></option>
                        </template>
                    </select>
                </label>
                <label class="flex flex-col gap-2 text-sm font-medium text-slate-700">
                    Billing interval
                    <select x-model="intervalFilter" @change="applyFilters()"
                        class="rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-700 focus:border-sky-300 focus:outline-none focus:ring-2 focus:ring-sky-200">
                        <template x-for="option in intervalOptions" :key="option.value">
                            <option :value="option.value" x-text="option.label"></option>
                        </template>
                    </select>
                </label>
            </div>
        </section>

        <section class="overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-black/5">
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-slate-200 text-left text-sm">
                    <thead class="bg-slate-50 text-xs font-semibold uppercase tracking-wide text-slate-500">
                        <tr>
                            <th scope="col" class="px-4 py-2">Template</th>
                            <th scope="col" class="px-4 py-2">Currency</th>
                            <th scope="col" class="px-4 py-2">Interval</th>
                            <th scope="col" class="px-4 py-2">Allowances</th>
                            <th scope="col" class="px-4 py-2">Rates</th>
                            <th scope="col" class="px-4 py-2">Updated</th>
                            <th scope="col" class="px-4 py-2">Actions</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-slate-100 bg-white text-slate-600">
                        <template x-if="loading">
                            <tr>
                                <td colspan="7" class="px-4 py-6 text-center text-sm text-slate-500">
                                    <div class="inline-flex items-center gap-2">
                                        <svg class="h-4 w-4 animate-spin text-slate-400" viewBox="0 0 24 24" fill="none"
                                            stroke="currentColor" stroke-width="2">
                                            <path stroke-linecap="round" stroke-linejoin="round"
                                                d="M12 3v3m6.364 1.636-2.121 2.121M21 12h-3m-1.636 6.364-2.121-2.121M12 21v-3m-6.364-1.636 2.121-2.121M3 12h3m1.636-6.364 2.121 2.121" />
                                        </svg>
                                        Loading templates…
                                    </div>
                                </td>
                            </tr>
                        </template>
                        <template x-if="!loading && !templates.length">
                            <tr>
                                <td colspan="7" class="px-4 py-6 text-center text-sm text-slate-500">
                                    No templates found. Create one to get started.
                                </td>
                            </tr>
                        </template>
                        <template x-for="template in templates" :key="template.id">
                            <tr class="hover:bg-slate-50">
                                <td class="whitespace-nowrap px-4 py-2">
                                    <div class="font-semibold text-slate-900"
                                        x-text="template.display_name || template.name"></div>
                                    <div class="text-xs text-slate-400">#<span x-text="template.name"></span></div>
                                    <template x-if="template.description">
                                        <div class="mt-1 max-w-xs truncate text-xs text-slate-400"
                                            x-text="template.description"></div>
                                    </template>
                                </td>
                                <td class="whitespace-nowrap px-4 py-2" x-text="template.currency"></td>
                                <td class="whitespace-nowrap px-4 py-2"
                                    x-text="intervalLabel(template.billing_interval)"></td>
                                <td class="whitespace-nowrap px-4 py-2">
                                    <div class="flex flex-col text-xs">
                                        <span><span class="font-semibold"
                                                x-text="formatNumber(template.included_minutes)"></span> minutes</span>
                                        <span><span class="font-semibold"
                                                x-text="formatNumber(template.included_messages)"></span>
                                            messages</span>
                                    </div>
                                </td>
                                <td class="whitespace-nowrap px-4 py-2">
                                    <div class="flex flex-col text-xs">
                                        <span>Overage <span class="font-semibold"
                                                x-text="formatCurrency(template.overage_rate_per_minute, template.currency)"></span>/min</span>
                                        <span>Setup <span class="font-semibold"
                                                x-text="formatCurrency(template.setup_fee, template.currency)"></span></span>
                                        <span>Tax <span class="font-semibold"
                                                x-text="formatPercent(template.tax_percent)"></span></span>
                                    </div>
                                </td>
                                <td class="whitespace-nowrap px-4 py-2 text-slate-500"
                                    x-text="formatDate(template.updated_at)"></td>
                                <td class="whitespace-nowrap px-4 py-2">
                                    <div class="flex items-center gap-2">
                                        <a :href="detailUrl(template.id)"
                                            class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-3 py-1 text-xs font-semibold text-slate-600 transition hover:border-sky-300 hover:text-sky-700">
                                            View
                                        </a>
                                        <button type="button"
                                            class="inline-flex items-center gap-1 rounded-lg border border-rose-200 px-3 py-1 text-xs font-semibold text-rose-600 transition hover:bg-rose-50"
                                            :disabled="processing.delete === template.id"
                                            @click="confirmDelete(template)">
                                            Delete
                                        </button>
                                    </div>
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </div>

            <template x-if="pagination">
                <div
                    class="flex items-center justify-between border-t border-slate-200 px-4 py-3 text-xs text-slate-500">
                    <div>
                        Showing <span class="font-semibold" x-text="pagination.showing_from"></span>
                        – <span class="font-semibold" x-text="pagination.showing_to"></span>
                        of <span class="font-semibold" x-text="pagination.total_items"></span>
                    </div>
                    <div class="flex items-center gap-2">
                        <button type="button"
                            class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-3 py-1.5 font-semibold transition"
                            :class="pagination.has_prev ? 'text-slate-600 hover:border-sky-300 hover:text-sky-700' : 'cursor-not-allowed text-slate-300'"
                            :disabled="!pagination.has_prev" @click="prevPage()">
                            Prev
                        </button>
                        <div class="text-sm font-semibold text-slate-600">
                            Page <span x-text="pagination.current_page"></span> / <span
                                x-text="pagination.total_pages"></span>
                        </div>
                        <button type="button"
                            class="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-3 py-1.5 font-semibold transition"
                            :class="pagination.has_next ? 'text-slate-600 hover:border-sky-300 hover:text-sky-700' : 'cursor-not-allowed text-slate-300'"
                            :disabled="!pagination.has_next" @click="nextPage()">
                            Next
                        </button>
                    </div>
                </div>
            </template>
        </section>
    </div>
</div>

<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('billTemplatesPage', (options) => ({
            basePath: options.basePath || '/console',
            listEndpoint: `${options.basePath || '/console'}/bill-templates`,
            createUrl: options.createUrl || `${options.basePath || '/console'}/bill-templates/new`,
            filtersRaw: options.filters || {},
            keyword: '',
            currencyFilter: 'all',
            intervalFilter: 'all',
            currencyOptions: [],
            intervalOptions: [],
            templates: [],
            pagination: null,
            loading: false,
            error: null,
            flash: null,
            page: 1,
            perPage: 20,
            processing: {
                delete: null,
            },
            init() {
                this.loadFilterOptions();
                this.fetchTemplates();
            },
            loadFilterOptions() {
                const currencies = Array.isArray(this.filtersRaw.currencies) ? this.filtersRaw.currencies : [];
                const intervals = Array.isArray(this.filtersRaw.billing_intervals) ? this.filtersRaw.billing_intervals : [];
                this.currencyOptions = [{ value: 'all', label: 'Any currency' }]
                    .concat(currencies.map((value) => ({
                        value: String(value).toUpperCase(),
                        label: String(value).toUpperCase(),
                    })));
                this.intervalOptions = [{ value: 'all', label: 'Any interval' }]
                    .concat(intervals.map((value) => ({
                        value: String(value).toLowerCase(),
                        label: this.intervalLabel(value),
                    })));
            },
            buildParams() {
                return {
                    page: this.page,
                    per_page: this.perPage,
                    filters: {
                        q: this.keyword.trim() || undefined,
                        currency: this.currencyFilter !== 'all' ? this.currencyFilter : undefined,
                        billing_interval: this.intervalFilter !== 'all' ? this.intervalFilter : undefined,
                    },
                }
            },
            async fetchTemplates() {
                this.loading = true;
                this.error = null;
                try {
                    const response = await fetch(`${this.listEndpoint}`, {
                        method: 'POST',
                        headers: {
                            'Accept': 'application/json',
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(this.buildParams()),
                    });
                    const data = await response.json();
                    if (!response.ok) {
                        throw new Error(data?.message || 'Failed to load billing templates');
                    }

                    const items = Array.isArray(data?.items) ? data.items : [];

                    const perPageRaw = Number(data?.per_page);
                    const totalItemsRaw = Number(data?.total_items);
                    const totalPagesRaw = Number(data?.total_pages);
                    const currentPageRaw = Number(data?.page);

                    const perPage = Number.isFinite(perPageRaw) && perPageRaw > 0 ? perPageRaw : this.perPage;
                    const totalItems = Number.isFinite(totalItemsRaw) && totalItemsRaw >= 0 ? totalItemsRaw : items.length;
                    const inferredTotalPages = Math.max(Math.ceil(totalItems / Math.max(perPage, 1)), 1);
                    const totalPages = Number.isFinite(totalPagesRaw) && totalPagesRaw >= 1
                        ? Math.max(Math.min(totalPagesRaw, inferredTotalPages || 1), 1)
                        : inferredTotalPages;
                    const currentPage = Number.isFinite(currentPageRaw) && currentPageRaw >= 1
                        ? Math.min(currentPageRaw, totalPages)
                        : Math.min(this.page || 1, totalPages);

                    const hasPrevApi = typeof data?.has_prev === 'boolean' ? data.has_prev : null;
                    const hasNextApi = typeof data?.has_next === 'boolean' ? data.has_next : null;
                    const resultsCount = items.length;
                    const showingFrom = resultsCount ? ((currentPage - 1) * perPage) + 1 : 0;
                    const showingTo = resultsCount ? Math.min(showingFrom + resultsCount - 1, totalItems) : 0;
                    const hasPrev = hasPrevApi !== null ? hasPrevApi : currentPage > 1;
                    const hasNext = hasNextApi !== null ? hasNextApi : currentPage < totalPages;
                    const prevPage = hasPrev ? Math.max(currentPage - 1, 1) : null;
                    const nextPage = hasNext ? Math.min(currentPage + 1, totalPages) : null;

                    this.templates = items;
                    this.pagination = {
                        current_page: currentPage,
                        per_page: perPage,
                        total_items: totalItems,
                        total_pages: totalPages,
                        has_prev: hasPrev,
                        has_next: hasNext,
                        prev_page: prevPage,
                        next_page: nextPage,
                        showing_from: showingFrom,
                        showing_to: showingTo,
                    };
                    if (data?.filters && typeof data.filters === 'object') {
                        this.filtersRaw = data.filters;
                        this.loadFilterOptions();
                    }
                    this.perPage = perPage;
                    this.page = currentPage;
                    this.flash = null;
                } catch (err) {
                    console.error(err);
                    this.error = err?.message || 'Unable to load billing templates';
                    this.templates = [];
                    this.pagination = null;
                } finally {
                    this.loading = false;
                }
            },
            applyFilters() {
                this.page = 1;
                this.fetchTemplates();
            },
            resetFilters() {
                this.keyword = '';
                this.currencyFilter = 'all';
                this.intervalFilter = 'all';
                this.applyFilters();
            },
            goToPage(target) {
                if (!this.pagination) {
                    return;
                }
                const totalPages = this.pagination.total_pages || 1;
                const page = Math.min(Math.max(target, 1), totalPages);
                if (page === this.page) {
                    return;
                }
                this.page = page;
                this.fetchTemplates();
            },
            prevPage() {
                if (this.pagination?.has_prev) {
                    this.goToPage(this.pagination.prev_page || (this.page - 1));
                }
            },
            nextPage() {
                if (this.pagination?.has_next) {
                    this.goToPage(this.pagination.next_page || (this.page + 1));
                }
            },
            detailUrl(id) {
                return `${this.basePath}/bill-templates/${id}`;
            },
            formatDate(value) {
                if (!value) {
                    return '—';
                }
                const date = new Date(value);
                if (Number.isNaN(date.getTime())) {
                    return value;
                }
                return date.toLocaleString();
            },
            intervalLabel(value) {
                const normalized = String(value || '').toLowerCase();
                if (normalized === 'hourly') return 'Hourly';
                if (normalized === 'daily') return 'Daily';
                if (normalized === 'weekly') return 'Weekly';
                if (normalized === 'monthly') return 'Monthly';
                if (normalized === 'quarterly') return 'Quarterly';
                if (normalized === 'yearly') return 'Yearly';
                return value || 'Custom';
            },
            formatNumber(value) {
                if (value === null || value === undefined) {
                    return '0';
                }
                return Number(value).toLocaleString();
            },
            formatCurrency(value, currency) {
                const amount = Number(value || 0);
                const currencyCode = currency || 'USD';
                const formatter = new Intl.NumberFormat(undefined, {
                    style: 'currency',
                    currency: currencyCode,
                    minimumFractionDigits: 2,
                    maximumFractionDigits: 4,
                });
                return formatter.format(amount);
            },
            formatPercent(value) {
                const amount = Number(value || 0);
                return `${amount.toFixed(2)}%`;
            },
            confirmDelete(template) {
                if (!template || !template.id) {
                    return;
                }
                const label = template.display_name || template.name;
                window.dispatchEvent(new CustomEvent('console:confirm', {
                    detail: {
                        title: 'Delete billing template',
                        message: label
                            ? `Delete billing template ${label}? This action cannot be undone.`
                            : 'Delete this billing template? This action cannot be undone.',
                        confirmLabel: 'Delete',
                        cancelLabel: 'Cancel',
                        destructive: true,
                        onConfirm: () => this.deleteTemplate(template),
                    },
                }));
            },
            async deleteTemplate(template) {
                if (!template || !template.id) {
                    return;
                }
                this.processing.delete = template.id;
                this.error = null;
                try {
                    const response = await fetch(this.detailUrl(template.id), {
                        method: 'DELETE',
                        headers: {
                            'Accept': 'application/json',
                        },
                    });
                    const data = await response.json().catch(() => ({}));
                    if (!response.ok) {
                        throw new Error(data?.message || 'Failed to delete billing template');
                    }
                    this.flash = 'Billing template deleted.';
                    await this.fetchTemplates();
                } catch (err) {
                    console.error(err);
                    this.error = err?.message || 'Failed to delete billing template';
                } finally {
                    this.processing.delete = null;
                }
            },
        }));
    });
</script>

{% endblock %}